//данная программа генерирует файлы общих библиотек

#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <queue>

using namespace std;

#include "binfile.h"
#include "both.h"


Int64 fCount, fCountPre, fHalfMask;
Int8 fLen, fLenPre, n, nPre;
vector<Int8> CompArray;
vector<bool> MarkArray;
queue<Int64> classQ;

BinFile writer, reader;

//функция, которая по заданной f заполняет массив сложностей
inline void ExtractClass(const Int64 f) {
  classQ.push(f);
  while(!classQ.empty()) {
    Int64 fTmp = classQ.front(); classQ.pop();
    for(Int8 i = 0; i < Shift.size(); i++) {
      if (i != 0) fTmp = swapvars(fTmp, Shift[i], nPre);
      Int64 fTmp2 = fTmp, fTmp21 = fTmp, fTmp22 = fTmp, fTmp23 = fTmp, fTmp24 = fTmp;
      for(Int8 j = 0; j < Gray.size(); j++) {
        if (j != 0) {
          fTmp2 = negbyvar(fTmp2, Gray[j], nPre);
          fTmp21 = d1byvar(fTmp21, Gray[j], nPre);
          fTmp22 = d2byvar(fTmp22, Gray[j], nPre);
          fTmp23 = d3byvar(fTmp23, Gray[j], nPre);
          fTmp24 = d4byvar(fTmp24, Gray[j], nPre);
          if (CompArray[fTmp21] != CompArray[f]) {
            CompArray[fTmp21] = CompArray[f];
            classQ.push(fTmp21);
          }
          if (CompArray[fTmp22] != CompArray[f]) {
            CompArray[fTmp22] = CompArray[f];
            classQ.push(fTmp22);
          }
          if (CompArray[fTmp23] != CompArray[f]) {
            CompArray[fTmp23] = CompArray[f];
            classQ.push(fTmp23);
          }
          if (CompArray[fTmp24] != CompArray[f]) {
            CompArray[fTmp24] = CompArray[f];
            classQ.push(fTmp24);
          }
        }
        if (CompArray[fTmp2] != CompArray[f]) {
          CompArray[fTmp2] = CompArray[f];
          classQ.push(fTmp2);
        }
      }
    }
  }
}

inline void MarkClassBy(const Int64 f) {
  classQ.push(f);
  while(!classQ.empty()) {
    Int64 fTmp = classQ.front(); classQ.pop();
    for(Int8 i = 0; i < Shift.size(); i++) {
      if (i != 0) fTmp = swapvars(fTmp, Shift[i], n);
      Int64 fTmp2 = fTmp, fTmp21 = fTmp, fTmp22 = fTmp, fTmp23 = fTmp, fTmp24 = fTmp;
      for(Int8 j = 0; j < Gray.size(); j++) {
        if (j != 0) {
          fTmp2 = negbyvar(fTmp2, Gray[j], n);
          fTmp21 = d1byvar(fTmp21, Gray[j], n);
          fTmp22 = d2byvar(fTmp22, Gray[j], n);
          fTmp23 = d3byvar(fTmp23, Gray[j], n);
          fTmp24 = d4byvar(fTmp24, Gray[j], n);

          if (!MarkArray[fTmp21]) {
            MarkArray[fTmp21] = true;
            classQ.push(fTmp21);
          }
          if (!MarkArray[fTmp22]) {
            MarkArray[fTmp22] = true;
            classQ.push(fTmp22);
          }
          if (!MarkArray[fTmp23]) {
            MarkArray[fTmp23] = true;
            classQ.push(fTmp23);
          }
          if (!MarkArray[fTmp24]) {
            MarkArray[fTmp24] = true;
            classQ.push(fTmp24);
          }
        }
        if (!MarkArray[fTmp2]) {
          MarkArray[fTmp2] = true;
          classQ.push(fTmp2);
        }
      }
    }
  }
}

inline void LoadInfo() {
  ostringstream oss;
  nPre = n - 1;
  fLen = 1 << n;
  fLenPre = 1 << nPre;
  fCount = (Int64)1 << fLen;
  fCountPre = (Int64)1 << fLenPre;
  MarkArray.resize(fCount);
  CompArray.resize(fCountPre);

  fHalfMask = ((Int64)1 << (fLen >> 1)) - 1;

  oss << "binfile" << (int)nPre << "v.mbf";
  reader.open(oss.str(), BIN_FILE_READ);

  MakeAddArrays(nPre);

  for(Int32 f = 0; f < fCountPre; f++)
    if (CompArray[f] == 0) {
      Int32 tf;
      reader.read(tf);
      reader.read(CompArray[tf]);
      cout << tf << ' ' << f << endl;
      ExtractClass(tf);
    }

  oss.str("");
  oss << "binfile" << (int)n << "v.mbf";
  writer.open(oss.str(), BIN_FILE_WRITE);

  MakeAddArrays(n);

  cout << "Writing!" << endl;
}

inline void SaveInfo(const Int64 f, const Int8 fComp) {
  writer.write((Int32)f);
  writer.write(fComp);
}

#include "gen1_5.h"

int main () {
  n = 2;
  LoadInfo();

  Int8 fComp;

  for(Int64 f = 0; f < fCount; f++)
    if (NotMarked(f)) {
      FindComplexityOfTo(f,fComp);
      MarkClassBy(f);
      cout << f << endl;
      SaveInfo(f,fComp);
    }

  return 0;
}
